<template>
    <div class="container" tabindex="1" @blur="blur" @focus="containerFocus">
        <input type="search" :disabled="disabled" :readonly="disabled" @input="inputChange" :value="valueRef"
               @keydown.enter.prevent
               @focus="focus" @blur="inutBlur" class="form-control" :placeholder="placeholder" ref="elementRef">
        <transition-group name="slide-down">
            <ul class="content-view no-result" v-if="showNoResultRef">
                <li>没有搜索到结果</li>
            </ul>
            <ul class="content-view" v-if="showContentRef && listRef.length" ref="viewRef" @scroll="handleScroll">
                <li v-for="item in listRef"
                    :class="{active:valueRef === item.valueName}"
                    :ref="el => valueRef === item.valueName && scrollToSelfFn(el)"
                    @click="chooseItem(item)">{{ item.valueName }}
                </li>
            </ul>
        </transition-group>
    </div>
</template>

<script>
import {nextTick, ref, watchEffect} from 'vue';
import {clone, get, post} from "../../../../util";
import {debounce} from "../../util";
import {registerValidate} from "../../form-validator";

export default {
    props: {
        id: [String, Number],
        name: String,
        url: String,
        modelValue: Object,
        searchContent: String,
        method: String,
        pageSize: Number,
        params: Object,
        beforeSend: Function,
        emptySearch: Boolean,
        placeholder: String,
        responseHandler: Function,
        disabled: Boolean,
        readonly: Boolean,
        validateRule: Object
    },
    setup(props, {emit}) {
        const valueRef = ref(""); // 输入框内容
        const showContentRef = ref(false); // 是否显示容器的控制器
        const listRef = ref([]); // 数据列表
        const viewRef = ref(); // 容器
        const showNoResultRef = ref(false); // 没有搜索结果的的控制器
        const elementRef = ref({});
        let currentPage = 1;
        let selectValue = {};
        let _cacheParams = {};
        let canNext = true;
        let canBlur = true;

        registerValidate({ref: elementRef, props, valueKey: 'id'}, 'name', valueRef);

        watchEffect(initProps);

        function inputChange(e) {
            valueRef.value = e.target.value;
            selectValue = {};
            initQuery();
        }

        function initProps() {
            const {id, name, modalValue} = props;
            if (modalValue || (id && name) || id == null) {
                selectValue = modalValue || {
                    valueCode: props.id,
                    valueName: id == null ? '' : props.name || ''
                }
                valueRef.value = selectValue.valueName;
            }
        }

        const initQuery = debounce(function () {
            if (!valueRef.value.trim() && !props.emptySearch) { // 清空内容时，列表也会被清空
                listRef.value = [];
                setValue();
                return;
            }
            currentPage = 1;
            listRef.value = [];
            _cacheParams = {};
            selectScrollTop = liveScrollTop = 0;
            let param = props.params || {};
            if (props.searchContent) {
                param[props.searchContent] = valueRef.value;
            }

            query(param, currentPage, searchTime = Date.now());
        }, 200);

        let liveScrollTop, selectScrollTop;

        function handleScroll(e) {
            let target = e.target;
            if ((target.scrollHeight - (target.scrollTop + target.clientHeight) < 10) && canNext) {
                canNext = false;
                nextPage();
            }
            liveScrollTop = target.scrollTop;
        }

        function chooseItem(item) {
            showContentRef.value = false;
            selectScrollTop = liveScrollTop;
            setValue(item);
        }

        function nextPage() {
            return query(_cacheParams, currentPage + 1);
        }

        function setValue(value = {}) {
            selectValue = value;
            valueRef.value = value.valueName || '';
            emit('update:id', value.valueCode);
            emit('update:name', value.valueName);
            emit('update:modelValue', value);
            emit('change', value);
        }

        function blur() {
            showContentRef.value = false;
            showNoResultRef.value = false;
            if (typeof selectValue.valueCode === 'undefined' || selectValue.valueCode === '') {
                setValue()
            }
        }

        function inutBlur(e) {
            setTimeout(() => canBlur && blur(), 100)
        }

        function containerFocus() {
            canBlur = false;
        }

        function focus() {
            canBlur = true;
            showContentRef.value = true;
            nextTick(() => {
                if (viewRef.value && selectScrollTop) { // 根据记录的位置信息，将打开的ul滚动条位置还原
                    viewRef.value.scrollTop = selectScrollTop;
                }
            });
            if (!listRef.value || !listRef.value.length) {
                if (props.emptySearch) {
                    initQuery();
                }
            }
        }

        let searchTime;

        async function query(params, pageIndex = 1, now) {
            params = clone(params || {});// clone
            params.pageSize = props.pageSize || 15;
            showNoResultRef.value = false;
            let getData;
            if (props.url) {
                const ajax = props.method === 'get' ? get : post;
                getData = (data) => ajax(props.url, data);
            } else if (typeof props.getData === 'function') {
                getData = props.getData;
            }
            pageIndex = Math.abs(pageIndex);
            params.currPage = pageIndex;
            if (typeof props.beforeSend === 'function') {
                params = props.beforeSend(params) || params;
            }

            let result = await Promise.resolve(getData(params));

            if (typeof props.responseHandler === 'function') {
                result = props.responseHandler(result) || result;
            }
            if (now !== searchTime) {
                return result;
            }
            if (+result.code === 0) {
                _cacheParams = params; // 缓存参数
                const {rows, totalPage} = result.data || {};
                // 设置组件数据
                listRef.value = [...listRef.value, ...(rows || [])];
                showNoResultRef.value = !listRef.value.length;
                currentPage = pageIndex;
                canNext = pageIndex < totalPage; // 如果当前页还不是最后一页，则还可以允许继续请求
            } else {
                alert(result.msg);
            }

            return result;
        }

        function scrollToSelfFn(el) {
            nextTick(() => {
                el && el.scrollIntoViewIfNeeded();
            })
        }

        // 还原重新初始化组件
        function rollback() {
            listRef.value = [];
            setValue();
        }

        return {
            valueRef, listRef, viewRef, showContentRef, showNoResultRef, elementRef, scrollToSelfFn,
            chooseItem, blur, focus, inutBlur, inputChange, handleScroll, containerFocus, rollback
        }
    }
}
</script>
<style scoped lang="less">
ul, li {
    padding: 0;
    margin: 0;
    list-style: none
}

.container {
    position: relative;
    border: none;
    outline: none;

    input {
        width: 100%;
        box-sizing: border-box;
    }
}

.content-view {
    width: 100%;
    max-height: 280px;
    overflow: auto;
    position: absolute;
    left: 0;
    top: 100%;
    margin-top: -1px;
    background: #fff;
    z-index: 9999;
    border: 1px solid #ccc;
    box-sizing: border-box;
    box-shadow: 0 5px 10px rgba(0, 0, 0, .25);
    border-radius: 0 0 5px 5px;

    &.no-result {
        pointer-events: none;
    }

    li {
        width: 100%;
        height: 32px;
        line-height: 32px;
        text-indent: 10px;
        cursor: pointer;

        &:hover {
            background: #e8e8e8;
        }

        &.active {
            color: #fff;
            background: #3c6bff;
        }
    }
}
</style>
